#pragma once

#include <AVUIBrush.h>
#include <AVUIGradientStop.h>
#include <AVUIObjectCollection.h>

namespace AVUI {

class GradientStopCollection : public TObjectCollection<GradientStop>
{
public:
    DECLARE_ELEMENT(GradientStopCollection, ObjectCollectionBase);
};

class GradientBrush : public Brush
{
public:

    DECLARE_ELEMENT(GradientBrush, Brush);

    DECLARE_DEPENDENCY_PROPERTY(MappingMode);
    BrushMappingMode::Enum get_MappingMode() { return (BrushMappingMode::Enum)(AVUI::UnboxValue<int>(GetValue(get_MappingModeProperty()))); }
    void set_MappingMode(BrushMappingMode::Enum value) { SetValue(get_MappingModeProperty(), AVUI::BoxValue<int>(value)); } 

    DECLARE_DEPENDENCY_PROPERTY(SpreadMethod);
    GradientSpreadMethod::Enum get_SpreadMethod() { return (GradientSpreadMethod::Enum)(AVUI::UnboxValue<int>(GetValue(get_SpreadMethodProperty()))); }
    void set_SpreadMethod(GradientSpreadMethod::Enum value) { SetValue(get_SpreadMethodProperty(), AVUI::BoxValue<int>(value)); } 

    DECLARE_READONLY_PROPERTY(GradientStops, GradientStopCollection, true);
    GradientStopCollection* get_GradientStops() { return &m_gradients; }
    const GradientStopCollection* get_GradientStops() const { return &m_gradients; }

protected:

    GradientBrush() : m_mappingMode(BrushMappingMode::RelativeToBoundingBox), m_spreadMethod(GradientSpreadMethod::Pad), m_gradients(this) { };
    ~GradientBrush() { m_gradients.InvalidateWeakReferences(); };

    virtual void OnGradientStopsChanged() = 0;

private:
    static void StaticConstructor();

    static void OnMappingModeChanged(Object* pDO, DependencyPropertyChangedEventArgs* e);
    static void OnSpreadMethodChanged(Object* pDO, DependencyPropertyChangedEventArgs* e);

    void OnGradientStopAdded(GradientStop* pAdd)
    {
        pAdd->add_Changed(EventHandler::Create(this, &GradientBrush::OnGradientStopChangedEvent));

        OnGradientStopsChanged();
    }

    void OnGradientStopRemoved(GradientStop* pRemove)
    {
        pRemove->remove_Changed(EventHandler::Create(this, &GradientBrush::OnGradientStopChangedEvent));

        OnGradientStopsChanged();
    }

    void OnGradientStopChangedEvent(Object* pObject, EventArgs* pArgs)
    {
        OnGradientStopsChanged();
    }


    class GradientBrushGradientStopCollection : public GradientStopCollection
    {
    public:
        GradientBrushGradientStopCollection(GradientBrush* pOwner) : m_pOwner(pOwner) { }

	protected:

		virtual void ClearItems()
		{
			for(int idx = 0; idx < get_Count(); idx++)
			{
				OnRemove((*this)[idx]);
			}

			GradientStopCollection::ClearItems();
		}

		virtual void InsertItem(int index, GradientStop* pItem)
		{
			GradientStopCollection::InsertItem(index, pItem);

			OnAdd(pItem);
		}

		virtual void RemoveItem(int index)
		{
			TRefCountedPtr<GradientStop> pOldValue = (*this)[index];
			GradientStopCollection::RemoveItem(index);

			OnRemove(pOldValue);
		}

		virtual void SetItem(int index, GradientStop* pItem)
		{
			TRefCountedPtr<GradientStop> pOldValue = (*this)[index];
			GradientStopCollection::SetItem(index, pItem);

			OnRemove(pOldValue);
			OnAdd(pItem);
		}

    private:
        void OnAdd(GradientStop* pAdd) { if(m_pOwner != NULL) m_pOwner->OnGradientStopAdded(pAdd); }
        void OnRemove(GradientStop* pRemove) { if(m_pOwner != NULL) m_pOwner->OnGradientStopRemoved(pRemove); }

        GradientBrush* m_pOwner;
    };

    BrushMappingMode::Enum m_mappingMode;
    GradientSpreadMethod::Enum m_spreadMethod;

    GradientBrushGradientStopCollection m_gradients;
};

typedef TRefCountedPtr<GradientBrush> GradientBrushPtr;

}; // namespace AVUI
